using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using Edmx.Utility;

namespace Edmx.Storage
{
    [DebuggerDisplay("Namespace={Namespace}, Alias={Alias}")]
    [XmlType(Namespace = EdmxConstants.StorageSchemaNamespace)]
    [XmlRoot("Schema", Namespace = EdmxConstants.StorageSchemaNamespace, IsNullable = false)]
    public class StoreSchema : MetadataEntityBase<StoreSchema>
    {
        public StoreSchema()
        {
            Functions = new FunctionCollection();
            EntityContainers = new EntityContainerCollection();
            EntityTypes = new EntityTypeCollection();
            Associations = new AssociationCollection();
        }

        [XmlElement("EntityContainer")]
        public EntityContainerCollection EntityContainers { get; set; }

        [XmlElement("EntityType")]
        public EntityTypeCollection EntityTypes { get; set; }

        [XmlElement("Association")]
        public AssociationCollection Associations { get; set; }

        [XmlElement("Function")]
        public FunctionCollection Functions { get; set; }

        [XmlAttribute("Namespace")]
        public string Namespace { get; set; }

        [XmlAttribute("Alias")]
        public string Alias { get; set; }

        [XmlAttribute("Provider")]
        public string Provider { get; set; }

        [XmlAttribute("ProviderManifestToken")]
        public string ProviderManifestToken { get; set; }

        #region Load & Save

        private static XmlSerializer _serializer;

        private static XmlSerializer Serializer
        {
            get
            {
                if (_serializer == null)
                    _serializer = new XmlSerializer(typeof(StoreSchema));
                return _serializer;
            }
        }

        private static XmlWriterSettings _xmlWriterSettings;

        private static XmlWriterSettings XmlWriterSettings
        {
            get
            {
                if (_xmlWriterSettings == null)
                    _xmlWriterSettings = new XmlWriterSettings { Indent = true, Encoding = Encoding.UTF8 };
                return _xmlWriterSettings;
            }
        }

        public virtual void SaveToFile(string fileName)
        {
            using (var writer = XmlWriter.Create(fileName, XmlWriterSettings))
                Save(writer);
        }

        public virtual string SaveToString()
        {
            var sb = new StringBuilder();

            using (var sw = new StringEncodingWriter(sb, Encoding.UTF8))
            using (var writer = XmlWriter.Create(sw, XmlWriterSettings))
                Save(writer);

            return sb.ToString();
        }

        private void Save(XmlWriter writer)
        {
            var xmlNamespaces = new XmlSerializerNamespaces();
            xmlNamespaces.Add("", EdmxConstants.StorageSchemaNamespace);
            xmlNamespaces.Add("store", EdmxConstants.StoreGeneratorNamespace);

            Serializer.Serialize(writer, this, xmlNamespaces);
            writer.Flush();
        }

        public static StoreSchema LoadFromFile(string fileName)
        {
            using (var fs = File.OpenRead(fileName))
            using (var reader = XmlReader.Create(fs))
                return Load(reader);
        }

        public static StoreSchema LoadFromString(string xml)
        {
            using (var sr = new StringReader(xml))
            using (var reader = XmlReader.Create(sr))
                return Load(reader);
        }

        private static StoreSchema Load(XmlReader reader)
        {
            return Serializer.Deserialize(reader) as StoreSchema;
        }

        #endregion
    }
}